/* Counting Semaphore in Java is a synchronizer which allows to impose a bound on resource is 
 * added in Java 5 along with other popular concurrent utilities like CountDownLatch, CyclicBarrier 
 * and Exchanger etc. Counting Semaphore in Java maintains specified number of pass or permits, 
 * In order to access a shared resource, Current Thread must acquire a permit. 
 * If permit is already exhausted by other thread than it can wait until a permit is available due 
 * to release of permit from different thread. This concurrency utility can be very useful to implement
 * producer consumer design pattern or implement bounded pool or resources like Thread Pool, DB Connection pool etc. 
 * java.util.Semaphore class represent a Counting semaphore which is initialized with number of permits. 
 * Semaphore provides two main method acquire() and release() for getting permits and releasing permits. 
 * acquire() method blocks until permit is available. Semaphore provides both blocking method as well as 
 * unblocking method to acquire permits. This Java concurrency tutorial focus on a very simple example 
 * of Binary Semaphore and demonstrate how mutual exclusion can be achieved using Semaphore in Java.

Counting Semaphore Example in Java (Binary Semaphore)
Java 5 Semaphore Example code Counting semaphore with one permit is known as binary semaphore 
because it has only two state permit available or permit unavailable. Binary semaphore can be used to 
implement mutual exclusion or critical section where only one thread is allowed to execute. 
Thread will wait on acquire() until Thread inside critical section release permit by calling release() on semaphore.
 */
import java.util.concurrent.Semaphore;

public class SemaphoreTest {

	Semaphore binary = new Semaphore(1);

	public static void main(String args[]) {
		final SemaphoreTest test = new SemaphoreTest();
		new Thread() {
			@Override
			public void run() {
				test.mutualExclusion();
			}
		}.start();

		new Thread() {
			@Override
			public void run() {
				test.mutualExclusion();
			}
		}.start();

	}

	private void mutualExclusion() {
		try {
			binary.acquire();

			// mutual exclusive region
			System.out.println(Thread.currentThread().getName()
					+ " inside mutual exclusive region");
			Thread.sleep(1000);

		} catch (InterruptedException ie) {
			ie.printStackTrace();
		} finally {
			binary.release();
			System.out.println(Thread.currentThread().getName()
					+ " outside of mutual exclusive region");
		}
	}

}
